#pragma once;

#include "common.h"

#include "obb.h"

class SpringBody;
class World;


struct BBox
{
	real xmin, ymin;
	real xmax, ymax;

	SpringBody *parent;

	public:


	bool intersects(BBox *second)
	{

		return !( 
			this->xmin > second->xmax  || this->xmax < second->xmin || 
			this->ymin > second->ymax  || this->ymax < second->ymin
			);

	}

	// can rectangle (1) entirely contain the other rectangle (2)?
	bool contains(BBox *second)
	{
		return (this->xmin < second->xmin && this->xmax > second->xmax &&
				this->ymin < second->ymin && this->ymax > second->ymax);
	}

	void draw();


};

class Particle
{
private:
	friend World;

	Particle()
	{
		init(0,0);
	}

	Particle(real x, real y)
	{
		init(x,y);
	}
public:
	Vec2f pos;
	Vec2f oldPos;
	Vec2f acceleration;
	Vec2f forceAccum;
	real massInverse;
	Vec2f velocity;
	real speed;
	SpringBody *parentBody;



	void init(real x, real y)
	{
		massInverse = 1.0;
		pos.is(x,y);
		oldPos = pos;
		acceleration.is(0,0);
		forceAccum.is(0,0);
		velocity.is(0,0);
		parentBody = 0x0;
	}

	bool inUse(){ return parentBody != 0x0; }


};

class Edge
{
public:
	Particle *particles[2];
	SpringBody *parent;
	real originalLength;
	bool isBoundary;

	Edge();
	Edge( Particle *p1, Particle *p2 );
	void init( Particle *p1, Particle *p2 );

	bool inUse(){ return parent != 0x0; }

};


class SpringBody
{

public:
	SpringBody();
	std::vector< Particle* > particles;
	std::vector< Edge* > edges;
	Vec2f centroid;
	Vec2f oldCentroid;
	std::string name;
	bool isColliding;
	BBox bounds;
	OBB2D obb;
	bool isFrozen;
	bool isAlive;
	


	void addParticle( Particle *p )
	{
		particles.push_back(p);
		p->parentBody = this;
	}

	void addEdge( Edge *e )
	{
		e->parent = this;
		edges.push_back(e);
	}

	void draw();
	void calcCenter();
	void addForce( Vec2f &force );
	void setFrozen();
	bool bodiesOverlap(SpringBody *other);
	void calcBoundryEdges();
	bool inUse(){ return isAlive; }
	void setUnused();
	BBox* getBounds();
	OBB2D *getOBB();
	

	// Based on code by Bennedict Bitterli, NooNooPhysics V1.0 engine
	void rotate(real rotation, real cx, real cy, bool conserveSpeed=true)
	{
		for(size_t i=0; i<particles.size(); i++)
		{
			Particle *p = particles[i];
			real vx = p->pos.x() - cx;
			real vy = p->pos.y() - cy;

			real radius = sqrt( vx*vx + vy*vy );
			real angle = atan2(vy,vx);

			vx = cx + radius * cos(angle + rotation) - p->pos.x();
			vy = cy + radius * sin(angle + rotation) - p->pos.y();

			p->pos += Vec2f(vx,vy);

			if( conserveSpeed )
			{
				p->oldPos += Vec2f(vx,vy);
			}
		}
	}


};

